package socket

import (
	"context"
	"errors"
	"fmt"
	"log/slog"
	"net"
)

type Server interface {
	Bind() error
	Listen() (*Socket, error)
	Listener() net.Listener
	ListenAddr() net.Addr
	Close() error
}

type TcpServer struct {
	addr       string
	ctx        context.Context
	listenAddr *net.TCPAddr
	listenTcp  *net.TCPListener
}

// NewTcpServer 设置tcp监听地址, 如 localhost:8080、127.0.0.1:8080、0.0.0.0:8080、:8080
func NewTcpServer(addr string) *TcpServer {
	return NewTcpServerContext(context.Background(), addr)
}

func NewTcpServerContext(ctx context.Context, addr string) *TcpServer {
	return &TcpServer{addr: addr, ctx: ctx}
}

func (t *TcpServer) Bind() error {
	tcpAddr, err := net.ResolveTCPAddr("tcp", t.addr)
	if err != nil {
		return err
	}
	if t.listenTcp, err = net.ListenTCP("tcp", tcpAddr); err != nil {
		return err
	}
	if tcpAddr.Port == 0 {
		// 随机端口
		t.listenAddr = t.listenTcp.Addr().(*net.TCPAddr)
		t.addr = t.listenAddr.String()
	} else {
		t.listenAddr = tcpAddr
	}
	slog.Info("Start the TCP socket at address " + t.addr)
	return nil
}

func (t *TcpServer) Listen() (*Socket, error) {
	select {
	case <-t.ctx.Done():
		_ = t.Close()
		return nil, errors.New("context canceled")
	default:
		conn, err := t.listenTcp.Accept()
		if err != nil {
			return nil, err
		}
		slog.Debug(fmt.Sprintf("TCP server connection established successfully %s->%s", conn.RemoteAddr(), conn.LocalAddr()))
		return NewSocket(conn), nil
	}
}

func (t *TcpServer) Listener() net.Listener {
	return t.listenTcp
}

func (t *TcpServer) Close() error {
	if t.listenTcp != nil {
		slog.Debug("Close TCP server " + t.addr)
		return t.listenTcp.Close()
	}
	return nil
}

func (t *TcpServer) ListenAddr() net.Addr {
	return t.listenAddr
}

type UdpServer struct {
	addr       string
	ctx        context.Context
	listenAddr *net.UDPAddr
	udpConn    *net.UDPConn
}

func NewUdpServer(addr string) *UdpServer {
	return NewUdpServerContext(context.Background(), addr)
}

func NewUdpServerContext(ctx context.Context, addr string) *UdpServer {
	return &UdpServer{ctx: ctx, addr: addr}
}

func (u *UdpServer) Bind() error {
	udpAddr, err := net.ResolveUDPAddr("udp", u.addr)
	if err != nil {
		return err
	}

	if udpConn, err := net.ListenUDP("udp", udpAddr); err != nil {
		return err
	} else {
		u.udpConn = udpConn
		u.listenAddr = udpConn.LocalAddr().(*net.UDPAddr)
		u.addr = u.listenAddr.String()
		slog.Info("Start the UDP socket at address " + u.addr)
		return nil
	}
}

func (u *UdpServer) Listen() (*Socket, error) {
	for {
		select {
		case <-u.ctx.Done():
			return nil, errors.New("context canceled")
		default:
			// 受限MTU大小, UDP接收缓冲区1500字节
			buf := make([]byte, 1500)
			if n, addr, err := u.udpConn.ReadFromUDP(buf); err != nil {
				return nil, err
			} else if n > 0 {
				slog.Debug(fmt.Sprintf("UDP server connection established successfully %s->%s", addr, u.listenAddr))
				return NewSocketUDP(u.udpConn, newUdpWrap(u.udpConn, addr, buf[:n])), nil
			}
		}
	}
}

func (u *UdpServer) Listener() net.Listener {
	return nil
}

func (u *UdpServer) Close() error {
	if u.udpConn != nil {
		slog.Debug("Close UDP server " + u.addr)
		return u.udpConn.Close()
	}
	return nil
}

func (u *UdpServer) UdpConn() *net.UDPConn {
	return u.udpConn
}

func (u *UdpServer) ListenAddr() net.Addr {
	return u.listenAddr
}
